package cn.demoncat.util.email;

import cn.demoncat.util.email.config.EmailProperties;
import cn.demoncat.util.email.constant.EmailLogs;
import cn.demoncat.util.email.constant.EmailMsgs;
import cn.demoncat.util.email.entity.EmailArg;
import cn.demoncat.util.exception.BizRuntimeException;
import cn.demoncat.util.exception.ParamRuntimeException;
import cn.demoncat.util.io.FreeMarkerUtil;
import cn.demoncat.util.lang.CollectionUtil;
import cn.demoncat.util.lang.LogUtil;
import cn.demoncat.util.lang.ParamEmptyUtil;
import cn.demoncat.util.lang.ParamValidUtil;
import cn.demoncat.util.lang.constant.CharsetConstant;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.entity.FileUrl;
import cn.demoncat.util.lang.msg.MsgMsg;
import cn.demoncat.util.web.config.AppProperties;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.mail.*;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.mail.internet.MimeUtility;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 邮件发送工具
 * 
 * 注意：部分邮箱系统，会过滤JS、内联CSS等，所以HTML邮件须使用行内样式。
 *
 * @author 延晓磊
 * 
 * @since 2018年1月4日
 */
@Component
public class EmailSendUtil {

	@Resource
	private EmailProperties emailProperties;
	@Resource
	private AppProperties appProperties;

	// SSL端口：阿里云等ECS会禁用25端口，所以通常使用 465
	private static final int SSL_PORT = 465;

	private static final Logger LOG = LogUtil.get(EmailSendUtil.class);

	/**
	 * 发送文本邮件
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject   邮件的主题
	 * @param content   邮件的内容(纯文本)
	 * @param to        接收者列表（1个发送失败，全部失败）
	 * 
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendText(String sender, String subject, String content, String... to) {
		sendTextFile(sender, subject, content, null, to);
	}

	/**
	 * 发送文本邮件-使用FreeMarker渲染主题和内容文本
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject	邮件的主题模板文本
	 * @param content	邮件的内容模板文本
	 * @param data		模板数据
	 * @param to		接收者列表（1个发送失败，全部失败）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月23日
	 */
	public void sendText(String sender, String subject, String content, Object data, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(subject,content);
		// FreeMarker渲染
		if (data != null) {
			// 标题模板
			if (subject.contains(StringConstant.DOLLAR)) {
				subject = FreeMarkerUtil.out(subject, data);
			}
			// 内容模板
			content = FreeMarkerUtil.out(content, data);
		}
		// 发送邮件
		sendText(sender, subject, content, to);
	}

	/**
	 * 发送文本邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateFile	邮件的内容模板文件：相对于模板根目录(通过email.template配置)，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 * 
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendTextByFtl(String sender, String subject, String templateFile, Object data, String... to) {
		sendTextByFtl(sender, subject, null, templateFile, data, to);
	}

	/**
	 * 发送文本邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateDir	邮件的内容模板目录：相对于模板根目录(通过email.template配置)，前缀/后缀非/
	 * @param templateFile	邮件的内容模板文件：相对于模板目录，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 * 
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendTextByFtl(String sender, String subject, String templateDir, String templateFile, Object data, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(templateFile);
		// 模板目录：项目路径 /xxx，磁盘路径 /webapps/xxx
		if (StringUtils.isBlank(templateDir)) {
			templateDir = emailProperties.getTemplate();
		} else {
			templateDir = emailProperties.getTemplate() + templateDir;
		}
		// 生成模板内容
		String content = FreeMarkerUtil.out(templateDir, templateFile, data);
		// 发送邮件
		sendText(sender, subject, content, to);
	}
	
	/**
	 * 发送Html邮件
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject   邮件的主题
	 * @param content   邮件的内容(Html文本)
	 * @param to       	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendHtml(String sender, String subject, String content, String... to) {
		sendHtmlFile(sender, subject, content, null, to);
	}

	/**
	 * 发送Html邮件-使用FreeMarker渲染主题和内容文本
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject	邮件的主题模板文本
	 * @param content	邮件的内容模板文本
	 * @param data		模板数据
	 * @param to		接收者列表（1个发送失败，全部失败）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月23日
	 */
	public void sendHtml(String sender, String subject, String content, Object data, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(subject,content);
		// FreeMarker渲染
		if (data != null) {
			// 标题模板
			if (subject.contains(StringConstant.DOLLAR)) {
				subject = FreeMarkerUtil.out(subject, data);
			}
			// 内容模板
			content = FreeMarkerUtil.out(content, data);
		}
		// 发送邮件
		sendHtml(sender, subject, content, to);
	}
	
	/**
	 * 发送Html邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateFile	邮件的内容模板文件：相对于模板根目录(通过email.template配置)，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendHtmlByFtl(String sender, String subject, String templateFile, Object data, String... to) {
		sendHtmlByFtl(sender, subject, null, templateFile, data, to);
	}
	
	/**
	 * 发送Html邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateDir	邮件的内容模板目录：相对于模板根目录(通过email.template配置)，前缀/后缀非/
	 * @param templateFile	邮件的内容模板文件：相对于模板目录，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendHtmlByFtl(String sender, String subject, String templateDir, String templateFile, Object data, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(templateFile);
		// 模板目录：项目路径 /xxx，磁盘路径 /webapps/xxx
		if (StringUtils.isBlank(templateDir)) {
			templateDir = emailProperties.getTemplate();
		} else {
			templateDir = emailProperties.getTemplate() + templateDir;
		}
		// 生成模板内容
		String content = FreeMarkerUtil.out(templateDir, templateFile, data);
		// 发送邮件
		sendHtml(sender, subject, content, to);
	}
	
	/**
	 * 发送带附件的文本邮件
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject   邮件的主题
	 * @param content 	邮件的内容(纯文本)
	 * @param files		邮件的附件{文件的URL地址:文件名称}
	 * @param to        接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendTextFile(String sender, String subject, String content, List<FileUrl> files, String... to) {
		// 创建多部件邮件
		send(new MultiPartEmail(), sender, subject, content, to, email ->{
			// 邮件内容
			email.setMsg(content);
			// 邮件附件
			if (CollectionUtils.isNotEmpty(files)) {
				EmailAttachment attachment;
				for (FileUrl file : files) {
					// 添加附件：添加多个即添加多附件
					attachment = new EmailAttachment();
					// 解决附件名中文乱码
					try {
						attachment.setName(MimeUtility.encodeText(file.getName()));
					} catch (UnsupportedEncodingException e) {
						throw new EmailException("编码附件名称出错：file = " + file.getName(), e);
					}
					try {
						attachment.setURL(new URL(file.getUrl()));
					} catch (MalformedURLException e) {
						throw new EmailException("编码附件URL出错：url = " + file.getUrl(), e);
					}
					email.attach(attachment);
				}
			}
		});
	}

	/**
	 * 发送带附件的文本邮件-使用FreeMarker渲染主题和内容文本
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject	邮件的主题模板文本
	 * @param content	邮件的内容模板文本
	 * @param data		模板数据
	 * @param files		邮件的附件{文件的URL地址:文件名称}
	 * @param to		接收者列表（1个发送失败，全部失败）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月23日
	 */
	public void sendTextFile(String sender, String subject, String content, Object data, List<FileUrl> files, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(subject,content);
		// FreeMarker渲染
		if (data != null) {
			// 标题模板
			if (subject.contains(StringConstant.DOLLAR)) {
				subject = FreeMarkerUtil.out(subject, data);
			}
			// 内容模板
			content = FreeMarkerUtil.out(content, data);
		}
		// 发送邮件
		sendTextFile(sender, subject, content, files, to);
	}
	
	/**
	 * 发送带附件的文本邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateFile	邮件的内容模板文件：相对于模板根目录(通过email.template配置)，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param files			邮件的附件{文件的URL地址:文件名称}
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendTextFileByFtl(String sender, String subject, String templateFile, Object data, List<FileUrl> files, String... to) {
		sendTextFileByFtl(sender, subject, null, templateFile, data, files, to);
	}
	
	/**
	 * 发送带附件的文本邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateDir	邮件的内容模板目录：相对于模板根目录(通过email.template配置)，前缀/后缀非/
	 * @param templateFile	邮件的内容模板文件：相对于模板目录，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param files			邮件的附件{文件的URL地址:文件名称}
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendTextFileByFtl(String sender, String subject, String templateDir, String templateFile, Object data, List<FileUrl> files, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(templateFile);
		// 模板目录：项目路径 /xxx，磁盘路径 /webapps/xxx
		if (StringUtils.isBlank(templateDir)) {
			templateDir = emailProperties.getTemplate();
		} else {
			templateDir = emailProperties.getTemplate() + templateDir;
		}
		// 生成模板内容
		String content = FreeMarkerUtil.out(templateDir, templateFile, data);
		// 发送邮件
		sendTextFile(sender, subject, content, files, to);
	}
	
	/**
	 * 发送带附件的Html邮件
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject	邮件的主题
	 * @param content	邮件的内容(Html文本)
	 * @param files		邮件的附件{文件的URL地址:文件名称}
	 * @param to     	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendHtmlFile(String sender, String subject, String content, List<FileUrl> files, String... to) {
		// 创建HTML邮件
		send(new HtmlEmail(), sender, subject, content, to, email ->{
			// 邮件内容(HTML)
			email.setHtmlMsg(content);
			// 邮件附件
			if (CollectionUtils.isNotEmpty(files)) {
				for (FileUrl file : files) {
					// 添加多次即多附件：解决附件名中文乱码
					try {
						email.embed(file.getUrl(), MimeUtility.encodeText(file.getName()));
					} catch (UnsupportedEncodingException e) {
						throw new EmailException("编码附件名称出错：file = " + file.getName(), e);
					}
				}
			}
		});
	}
	
	/**
	 * 发送带附件的Html邮件-使用FreeMarker渲染主题和内容文本
	 * 
	 * @param sender	发送者名称，默认为EmailProperties.sender
	 * @param subject	邮件的主题模板文本
	 * @param content	邮件的内容模板文本
	 * @param data		模板数据
	 * @param files		邮件的附件{文件的URL地址:文件名称}
	 * @param to		接收者列表（1个发送失败，全部失败）
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月23日
	 */
	public void sendHtmlFile(String sender, String subject, String content, Object data, List<FileUrl> files, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(subject,content);
		// FreeMarker渲染
		if (data != null) {
			// 标题模板
			if (subject.contains(StringConstant.DOLLAR)) {
				subject = FreeMarkerUtil.out(subject, data);
			}
			// 内容模板
			content = FreeMarkerUtil.out(content, data);
		}
		// 发送邮件
		sendHtmlFile(sender, subject, content, files, to);
	}
	
	/**
	 * 发送带附件的Html邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateFile	邮件的内容模板文件：相对于模板根目录(通过email.template配置)，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param files			邮件的附件{文件的URL地址:文件名称}
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendHtmlFileByFtl(String sender, String subject, String templateFile, Object data, List<FileUrl> files, String... to) {
		sendHtmlFileByFtl(sender, subject, null, templateFile, data, files, to);
	}
	
	/**
	 * 发送带附件的Html邮件-使用FreeMarker渲染内容模板
	 * 
	 * @param sender		发送者名称，默认为EmailProperties.sender
	 * @param subject    	邮件的主题
	 * @param templateDir	邮件的内容模板目录：相对于模板根目录(通过email.template配置)，前缀/后缀非/
	 * @param templateFile	邮件的内容模板文件：相对于模板目录，通常以.ftl后缀，如tmp.ftl
	 * @param data			模板数据
	 * @param files			邮件的附件{文件的URL地址:文件名称}
	 * @param to         	接收者列表（1个发送失败，全部失败）
	 *
	 * @author 延晓磊
	 * 
	 * @since 2018年1月4日
	 */
	public void sendHtmlFileByFtl(String sender, String subject, String templateDir, String templateFile, Object data, List<FileUrl> files, String... to) {
		// 参数校验
		ParamEmptyUtil.checkBlank(templateFile);
		// 模板目录：项目路径 /xxx，磁盘路径 /webapps/xxx
		if (StringUtils.isBlank(templateDir)) {
			templateDir = emailProperties.getTemplate();
		} else {
			templateDir = emailProperties.getTemplate() + templateDir;
		}
		// 生成模板内容
		String content = FreeMarkerUtil.out(templateDir, templateFile, data);
		// 发送邮件
		sendHtmlFile(sender, subject, content, files, to);
	}
	
	/**
	 * 发送邮件
	 * 
	 * @param data			邮件参数
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年7月17日
	 */
	public void send(EmailArg data) {
		// 邮件类型
		if (data.getHtml()) {
			// HTML
			if (data.getTemplate()) {
				// 模板渲染
				if (CollectionUtils.isEmpty(data.getFiles())) {
					// 不带附件
					if (StringUtils.isBlank(data.getContent())) {
						// 模板文件渲染
						sendHtmlByFtl(data.getSender(), data.getSubject(), data.getTemplateDir(), data.getTemplateFile(), data.getTemplateData(), data.getTo());
					}else {
						// 模板文本渲染
						sendHtml(data.getSender(), data.getSubject(), data.getContent(), data.getTemplateData(), data.getTo());
					}
				}else {
					// 带附件
					if (StringUtils.isBlank(data.getContent())) {
						// 模板文件渲染
						sendHtmlFileByFtl(data.getSender(), data.getSubject(), data.getTemplateDir(), data.getTemplateFile(), data.getTemplateData(), data.getFiles(), data.getTo());
					}else {
						// 模板文本渲染
						sendHtmlFile(data.getSender(), data.getSubject(), data.getContent(), data.getTemplateData(), data.getFiles(), data.getTo());
					}
				}
			}else {
				// 非模板渲染
				if (CollectionUtils.isEmpty(data.getFiles())) {
					// 不带附件
					sendHtml(data.getSender(), data.getSubject(), data.getContent(), data.getTo());
				}else {
					// 带附件
					sendHtmlFile(data.getSender(), data.getSubject(), data.getContent(), data.getFiles(), data.getTo());
				}
			}
		}else {
			// 文本
			if (data.getTemplate()) {
				// 模板渲染
				if (CollectionUtils.isEmpty(data.getFiles())) {
					// 不带附件
					if (StringUtils.isBlank(data.getContent())) {
						// 模板文件渲染
						sendTextByFtl(data.getSender(), data.getSubject(), data.getTemplateDir(), data.getTemplateFile(), data.getTemplateData(), data.getTo());
					}else {
						// 模板文本渲染
						sendText(data.getSender(), data.getSubject(), data.getContent(), data.getTemplateData(), data.getTo());
					}
				}else {
					// 带附件
					if (StringUtils.isBlank(data.getContent())) {
						// 模板文件渲染
						sendTextFileByFtl(data.getSender(), data.getSubject(), data.getTemplateDir(), data.getTemplateFile(), data.getTemplateData(), data.getFiles(), data.getTo());
					}else {
						// 模板文本渲染
						sendTextFile(data.getSender(), data.getSubject(), data.getContent(), data.getTemplateData(), data.getFiles(), data.getTo());
					}
				}
			}else {
				// 非模板渲染
				if (CollectionUtils.isEmpty(data.getFiles())) {
					// 不带附件
					sendText(data.getSender(), data.getSubject(), data.getContent(), data.getTo());
				}else {
					// 带附件
					sendTextFile(data.getSender(), data.getSubject(), data.getContent(), data.getFiles(), data.getTo());
				}
			}
		}
	}
	
	
	/**
	 * 初始化邮件
	 * 
	 * @param email
	 * @param sender
	 * @param subject
	 * @param content
	 * @param to
	 * @return
	 * @throws EmailException
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月23日
	 */
	private <T extends Email>T initEmail(T email, String sender, String subject, String content, String[] to) throws EmailException {
		// 参数校验
		ParamEmptyUtil.checkBlank(subject,content);
		// 清洗接收人
		String[] cleans = cleanTo(to);
		if (cleans == null) {
			throw EmailMsgs.SEND_EMAIL_TO_EX;
		}else{
			to = cleans;
		}
		// 设置字符集：默认只能发送ASCII，否则乱码
		email.setCharset(CharsetConstant.UTF8);
		// 设置SMTP服务器及其端口：通过百度搜索服务商的SMTP
		email.setHostName(emailProperties.getServer());
		email.setSmtpPort(emailProperties.getPort());
		// 传输加密
		if (emailProperties.getPort() == SSL_PORT) {
			// 设置使用SSL传输协议加密
			email.setSSLCheckServerIdentity(true);
			email.setSSLOnConnect(true);
		} else {
			// 设置使用TLS传输协议加密
			email.setStartTLSRequired(true);
			email.setStartTLSEnabled(true);
		}
		// 校验发送者
		email.setAuthenticator(new DefaultAuthenticator(emailProperties.getUsername(), emailProperties.getPassword()));
		// 打印日志在控制台
		email.setDebug(false);
		
		// 邮件标题
		email.setSubject(subject);
		// 发送者
		email.setFrom(emailProperties.getUsername(), sender, CharsetConstant.UTF8);
		// 接收者：单个或多个
		email.addTo(to);
		return email;
	}
	
	/**
	 * 清洗接收人
	 * 
	 * @param to
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年12月16日
	 */
	private static String[] cleanTo(String[] to) {
		// 非空
		if (ArrayUtils.isNotEmpty(to)) {
			// 去重，去空，去无效
			Set<String> list = new HashSet<>(to.length);
			for (String el : to) {
				if (StringUtils.isNotBlank(el) && ParamValidUtil.isEmail(el)) {
					list.add(el);
				}
			}
			if (CollectionUtils.isNotEmpty(list)) {
				return CollectionUtil.toStrArray(list);
			}
		}
		return null;
	}
	
	/**
	 * 发送邮件
	 * 
	 * @param email		原始邮件类型
	 * @param sender	发件人
	 * @param subject	主题
	 * @param content	内容
	 * @param to		接收人
	 * @param handler	邮件处理器
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月23日
	 */
	private <T extends Email>void send(T email, String sender, String subject, String content, String[] to, EmailHeader<T> handler) {
		try {
			// 默认发送人
			if (StringUtils.isBlank(sender)) {
				sender = emailProperties.getSender();
			}
			if (StringUtils.isBlank(sender)) {
				sender = appProperties.getApp();
			}
			// 邮件处理
			handler.handle(initEmail(email, sender, subject, content, to));
			// 发送邮件：会先连接所有接收者，有一个发送失败就会全部失败
			email.send();
			LOG.info(EmailLogs.SEND_EMAIL_SUCCESS, emailProperties.getUsername(), sender, subject, to);
		} catch (ParamRuntimeException e) {
			// 参数错误
			LOG.error(EmailLogs.SEND_EMAIL_ERROR, emailProperties.getUsername(), sender, subject, to, content, e);
			throw e;
		} catch (EmailException e) {
			// 邮箱服务错误，发送者认证错误，邮箱号错误，发送失败(多人发送时有一个失败就会部失败)
			LOG.error(EmailLogs.SEND_EMAIL_ERROR, emailProperties.getUsername(), sender, subject, to, content, e);
			throw new BizRuntimeException(MsgMsg.EMAIL_SEND_ERROR, e);
		}
	}
	
	/**
	 * 邮件处理器
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年4月23日
	 */
	private interface EmailHeader<T>{
		
		/**
		 * 设置发送内容
		 * 
		 * @param email
		 * @throws EmailException
		 * 
		 * @author 延晓磊
		 *
		 * @since 2020年4月23日
		 */
		void handle(T email) throws EmailException;
	}
	
}
